package com.wayhome.srpingbootmybatis.boc.service;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.sun.corba.se.spi.ior.IdentifiableFactory;
import com.wayhome.srpingbootmybatis.boc.consts.*;
import com.wayhome.srpingbootmybatis.boc.dto.*;
import com.wayhome.srpingbootmybatis.boc.util.SHA256WithRSAUtil;
import com.wayhome.srpingbootmybatis.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;

@Slf4j
@Service("bocNewChannelImpl")
public class BocNewChannelImpl {

    @Value("${boc.url:''}")
    private String bocUrl;

    @Value("${boc.bussId:''}")
    private String bussId;

    @Value("${boc.termId:''}")
    private String termId;

    @Value("${boc.privateKey:''}")
    private String privateKey;

    @Value("${boc.pubKey:''}")
    private String pubKey;

    @Resource
    private BocOrderService bocOrderService;

    @Resource
    private Jedis testMobilePaymentJedis;

    private static final String CYCLE_SEQ_KEY = "cycle:sequence";
    private static final Integer MAX_TRACE_NO = 999999;

    public static final String mchId = "104130159121426";

    private static final ObjectMapper mapper = new ObjectMapper();
    static {
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE);
    }


    public CodePayFixmedinsApiRespDO billpay(String authCode) throws Exception {
        log.info("==========>中行一码付支付交易");
        BocPayReqDTO bocPayReqDTO = new BocPayReqDTO();
        setDefaultProperties(bocPayReqDTO, mchId);
        //交易编码，选支付宝消费
        bocPayReqDTO.setTranId(BocTranEnum.TRAN_ZFB_PAY.getCode());
        //支付方式
        bocPayReqDTO.setPayType(BocPayTypeEnum.PAY_TYPE_ZFBA.getCode());
        //设备类型
        bocPayReqDTO.setDeviceType(BocOnePayConst.DEVICE_TYPE_11);
        //支付授权码
        bocPayReqDTO.setAuthCode(authCode);
        //交易金额
        String tranAmt = formatAmt("0.01");
        bocPayReqDTO.setTranAmt(tranAmt);
        //唯一支付流水号
        String payLs = genPayLs(bocPayReqDTO);
        bocPayReqDTO.setPayLs(payLs);
        //签名
        String sign = bocPayReqDTO.signStr();
        String SHA256SignStr = SHA256WithRSAUtil.sign(privateKey, sign);
        bocPayReqDTO.setSign(SHA256SignStr);

        String objectMapperJson = mapper.writeValueAsString(bocPayReqDTO);

        String content = sendHttpRequest(objectMapperJson, bocPayReqDTO.getTranId());
        BocPayRespDTO bocPayRespDTO = mapper.readValue(content, BocPayRespDTO.class);

        String signStr = bocPayRespDTO.signStr();
        boolean verifySign = SHA256WithRSAUtil.verifySign(pubKey, signStr, bocPayRespDTO.getSign());
        if (!verifySign) {
            throw new Exception("中行一码付付款，返回结果验签不通过");
        }

        //将支付结果异步保存到表中，以后查询要用到
        saveBocPayOrder(bocPayRespDTO, bocPayReqDTO.getTraceNo(),"H13040700421",payLs,payLs);
        BocResultDTO bocResultDTO = new BocResultDTO();
        BeanUtils.copyProperties(bocPayRespDTO,bocResultDTO);
        bocResultDTO.setOrderNo(bocPayRespDTO.getOrderNo());
        return payResult(bocResultDTO);
    }

    public CodePayFixmedinsApiRespDO billpayQuery(String oldPayLs) throws Exception {
        log.info("==========>一码付中行--查询支付订单");
        BocQueryOrdReqDTO bocQueryOrdReqDTO = new BocQueryOrdReqDTO();
        setDefaultProperties(bocQueryOrdReqDTO, mchId);
        //交易编码 支付结果查询:201006
        bocQueryOrdReqDTO.setTranId(BocTranEnum.TRAN_QUERY_ORD.getCode());
        //原支付方式
        bocQueryOrdReqDTO.setOldPayType(BocPayTypeEnum.PAY_TYPE_ZFBA.getCode());
        //原交易编码
        bocQueryOrdReqDTO.setOldTranId(BocTranEnum.TRAN_ZFB_PAY.getCode());
        //原唯一流水号
        bocQueryOrdReqDTO.setOldPayLs(oldPayLs);
        //原交易金额
        bocQueryOrdReqDTO.setOldTranAmt(formatAmt("0.08"));
        //唯一支付流水号
        String payLs = genPayLs(bocQueryOrdReqDTO);
        //原交易币种
        bocQueryOrdReqDTO.setOldCcyCode(BocOnePayConst.BOC_TRAN_CCY_CODE);
        //本次交易唯一流水号
        bocQueryOrdReqDTO.setPayLs(payLs);

        //签名
        String sign = bocQueryOrdReqDTO.signStr();
        String SHA256SignStr = SHA256WithRSAUtil.sign(privateKey, sign);
        bocQueryOrdReqDTO.setSign(SHA256SignStr);

        String objectMapperJson = mapper.writeValueAsString(bocQueryOrdReqDTO);

        String content = sendHttpRequest(objectMapperJson, bocQueryOrdReqDTO.getTranId());
        BocQueryOrdRespDTO bocQueryOrdRespDTO = mapper.readValue(content, BocQueryOrdRespDTO.class);
        BocResultDTO bocResultDTO = new BocResultDTO();
        BeanUtils.copyProperties(bocQueryOrdRespDTO, bocResultDTO);
        bocResultDTO.setOrderNo(bocQueryOrdRespDTO.getOldOrderNo());
        return queryResult(bocResultDTO);
    }

    public CodePayFixmedinsApiRespDO b2cPayRefund(BocRefundOrdReqDTO orderInfo) throws Exception {
        BocRefundOrdReqDTO bocRefundOrdReqDTO = new BocRefundOrdReqDTO();
        setDefaultProperties(bocRefundOrdReqDTO, mchId);
        //交易编码 退货交易：201005
        bocRefundOrdReqDTO.setTranId(BocTranEnum.TRAN_REFUND.getCode());
        //原支付方式：ZFBA-支付宝
        bocRefundOrdReqDTO.setOldPayType(BocPayTypeEnum.PAY_TYPE_ZFBA.getCode());
        //原银行日期
        bocRefundOrdReqDTO.setOldBankDate(orderInfo.getOldBankDate());
        //原商户订单号
        bocRefundOrdReqDTO.setOldOrderNo(orderInfo.getOldOrderNo());
        //原支付凭证号
        bocRefundOrdReqDTO.setOldPayVounum(orderInfo.getOldPayVounum());
        //退货金额
        bocRefundOrdReqDTO.setRefundAmt(orderInfo.getRefundAmt());
        //唯一支付流水号
        String payLs = genPayLs(bocRefundOrdReqDTO);
        bocRefundOrdReqDTO.setPayLs(payLs);
        //签名
        String sign = bocRefundOrdReqDTO.signStr();
        String SHA256SignStr = SHA256WithRSAUtil.sign(privateKey, sign);
        bocRefundOrdReqDTO.setSign(SHA256SignStr);

        String objectMapperJson = mapper.writeValueAsString(bocRefundOrdReqDTO);

        String content = sendHttpRequest(objectMapperJson, bocRefundOrdReqDTO.getTranId());

        BocRefundOrdRespDTO bocRefundOrdRespDTO = mapper.readValue(content, BocRefundOrdRespDTO.class);

        saveBocRefundOrder(bocRefundOrdRespDTO, bocRefundOrdRespDTO.getTraceNo(),"H13040700421",payLs,payLs);

        BocResultDTO bocResultDTO = new BocResultDTO();
        BeanUtils.copyProperties(bocRefundOrdRespDTO, bocResultDTO);
        bocResultDTO.setOrderNo(bocRefundOrdRespDTO.getRefundOrderNo());
        return refundResult(bocResultDTO);
    }

    public CodePayFixmedinsApiRespDO b2cPayRefundQuery(BocRefundOrdReqDTO orderInfo) throws Exception {
        BocQueryRefundOrdReqDTO bocQueryRefundOrdReqDTO = new BocQueryRefundOrdReqDTO();
        setDefaultProperties(bocQueryRefundOrdReqDTO, mchId);
        //交易编码
        bocQueryRefundOrdReqDTO.setTranId(BocTranEnum.TRAN_QUERY_REFUND.getCode());
        //原支付方式
        bocQueryRefundOrdReqDTO.setOldPayType(BocPayTypeEnum.PAY_TYPE_ZFBA.getCode());
        //原交易编码
        bocQueryRefundOrdReqDTO.setOldTranId(BocTranEnum.TRAN_REFUND.getCode());
        //原唯一流水号
        bocQueryRefundOrdReqDTO.setOldPayLs(orderInfo.getPayLs());
        //原交易金额
        bocQueryRefundOrdReqDTO.setOldTranAmt(orderInfo.getRefundAmt());
        //原交易币种
        bocQueryRefundOrdReqDTO.setOldCcyCode(BocOnePayConst.BOC_TRAN_CCY_CODE);
        //唯一支付流水号
        String payLs = genPayLs(bocQueryRefundOrdReqDTO);
        bocQueryRefundOrdReqDTO.setPayLs(payLs);
        //签名
        String sign = bocQueryRefundOrdReqDTO.signStr();
        String SHA256SignStr = SHA256WithRSAUtil.sign(privateKey, sign);
        bocQueryRefundOrdReqDTO.setSign(SHA256SignStr);

        String objectMapperJson = mapper.writeValueAsString(bocQueryRefundOrdReqDTO);

        String content = sendHttpRequest(objectMapperJson, bocQueryRefundOrdReqDTO.getTranId());

        BocQueryRefundOrdRespDTO bocQueryRefundOrdRespDTO = mapper.readValue(content, BocQueryRefundOrdRespDTO.class);
        BocResultDTO bocResultDTO = new BocResultDTO();
        BeanUtils.copyProperties(bocQueryRefundOrdRespDTO, bocResultDTO);
        bocResultDTO.setOrderNo(bocQueryRefundOrdRespDTO.getOldRefundOrderNo());
        return queryResult(bocResultDTO);
    }


    //设置默认参数
    private void setDefaultProperties(BocBaseFieldDTO bocBaseFieldDTO, String mchId) {
        //报文版本 默认1000
        bocBaseFieldDTO.setMsgVer(BocOnePayConst.MSG_VER);
        Date now = new Date();
        //前端系统日期
        bocBaseFieldDTO.setInDate(DateUtils.date2Str(now,DateUtils.YYYY_MM_DD_NONE));
        //前端系统时间
        bocBaseFieldDTO.setInTime(DateUtils.date2Str(now, DateUtils.HH_MM_SS_NONE));
        //业务编码
        bocBaseFieldDTO.setBussId(bussId);
        //接入商户类型
        bocBaseFieldDTO.setMerTp(MerTPEnum.MER_TP_01.getCode());
        //报文方向
        bocBaseFieldDTO.setDrctn(DrctnEnum.DRCTN_REQUEST.getCode());
        //商户号
        bocBaseFieldDTO.setMerId(mchId);
        //终端号
        bocBaseFieldDTO.setTermId(termId);
        //终端流水号
        bocBaseFieldDTO.setTraceNo(genTraceNo());
        //批次号
        bocBaseFieldDTO.setBatchNo(bocBaseFieldDTO.getInTime());

    }

    //格式化金额
    private String formatAmt(String tranAmt) {
        BigDecimal bigDecimal = new BigDecimal(tranAmt);
        long amtLong = bigDecimal.multiply(new BigDecimal("100")).longValue();
        return String.format("%012d", amtLong);
    }

    private synchronized String genTraceNo(){
        Long seqLongValue = testMobilePaymentJedis.incr(CYCLE_SEQ_KEY);
        if (Objects.nonNull(seqLongValue) && seqLongValue > MAX_TRACE_NO) {
            testMobilePaymentJedis.set(CYCLE_SEQ_KEY, "1");
            seqLongValue = 1L;
        }
        return String.format("%06d", seqLongValue);
    }

    private String genPayLs(BocBaseFieldDTO bocBaseFieldDTO) {
        return termId + bocBaseFieldDTO.getInDate() + bocBaseFieldDTO.getInTime() + bocBaseFieldDTO.getTraceNo();
    }

    private String sendHttpRequest(String request, String tranId) throws Exception {
        //创建实例
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //创建post请求
        HttpPost post = new HttpPost(bocUrl);
        //定义相应变量
        CloseableHttpResponse response = null;
        String content = "";
        try {

            StringEntity entity = new StringEntity(request, "GB2312");
            post.setHeader("Content-Type", "application/json");
            post.setEntity(entity);
            log.info("==========>发起中行请求。交易编码：{}, 请求参数： {}", tranId, request);
            response = httpClient.execute(post);
            content = EntityUtils.toString(response.getEntity(),"GBK");
            log.info("==========>发起中行请求。交易编码：{}, 返回结果： {}",tranId, content);
            return content;
        } catch (Exception e) {
            log.info("==========>发起中行请求，交易编码：{},调用http发送交易时产生错误：{}", tranId, e.getMessage(), e);
            return null;
        } finally {
            httpClient.close();
        }
    }

    private void saveBocPayOrder(BocPayRespDTO bocPayRespDTO, String setlId, String fixmedinsCode, String fixmedinsTrnsSn,
                                 String payLs) {

        BocOrderInfo bocPayOrderInfo = new BocOrderInfo();
        //机构编码
        bocPayOrderInfo.setFixmedinsCode(fixmedinsCode);
        //结算id
        bocPayOrderInfo.setSetlId(setlId);
        //定点机构交易流水号
        bocPayOrderInfo.setFixmedinsTrnsSn(fixmedinsTrnsSn);
        //交易类型
        bocPayOrderInfo.setTranType(BocOnePayConst.TRAN_TYPE_PAY);
        //支付交易唯一流水号
        bocPayOrderInfo.setPayLs(payLs);
        //批次号
        bocPayOrderInfo.setBatchNo(bocPayRespDTO.getBatchNo());
        //终端流水号
        bocPayOrderInfo.setTraceNo(bocPayRespDTO.getTraceNo());
        //支付方式
        bocPayOrderInfo.setPayType(BocPayTypeEnum.PAY_TYPE_ZFBA.getCode());
        //交易金额
        bocPayOrderInfo.setTranAmt(bocPayRespDTO.getTranAmt());
        //银行交易日期
        bocPayOrderInfo.setBankDate(bocPayRespDTO.getBankDate());
        //银行交易时间
        bocPayOrderInfo.setBankTime(bocPayRespDTO.getBankTime());
        //交易结果返回码
        bocPayOrderInfo.setRespCode(bocPayRespDTO.getRespCode());
        //交易结果描述
        bocPayOrderInfo.setRespMsg(bocPayRespDTO.getRespMsg());
        //商户订单号
        bocPayOrderInfo.setPayOrderNo(bocPayRespDTO.getOrderNo());
        bocOrderService.saveBocOrder(bocPayOrderInfo);
    }
    private void saveBocRefundOrder(BocRefundOrdRespDTO bocPayRespDTO, String setlId, String fixmedinsCode, String fixmedinsTrnsSn,
                                 String payLs) {

        BocOrderInfo bocPayOrderInfo = new BocOrderInfo();
        //机构编码
        bocPayOrderInfo.setFixmedinsCode(fixmedinsCode);
        //结算id
        bocPayOrderInfo.setSetlId(setlId);
        //定点机构交易流水号
        bocPayOrderInfo.setFixmedinsTrnsSn(fixmedinsTrnsSn);
        //交易类型
        bocPayOrderInfo.setTranType(BocOnePayConst.TRAN_TYPE_PAY);
        //支付交易唯一流水号
        bocPayOrderInfo.setPayLs(payLs);
        //批次号
        bocPayOrderInfo.setBatchNo(bocPayRespDTO.getBatchNo());
        //终端流水号
        bocPayOrderInfo.setTraceNo(bocPayRespDTO.getTraceNo());
        //支付方式
        bocPayOrderInfo.setPayType(BocPayTypeEnum.PAY_TYPE_ZFBA.getCode());
        //交易金额
        bocPayOrderInfo.setTranAmt(bocPayRespDTO.getRefundAmt());
        //银行交易日期
        bocPayOrderInfo.setBankDate(bocPayRespDTO.getBankDate());
        //银行交易时间
        bocPayOrderInfo.setBankTime(bocPayRespDTO.getBankTime());
        //交易结果返回码
        bocPayOrderInfo.setRespCode(bocPayRespDTO.getRespCode());
        //交易结果描述
        bocPayOrderInfo.setRespMsg(bocPayRespDTO.getRespMsg());
        //商户订单号
        bocPayOrderInfo.setPayOrderNo(bocPayRespDTO.getOldOrderNo());
        bocPayOrderInfo.setRefundOrderNo(bocPayRespDTO.getRefundOrderNo());
        bocOrderService.saveBocOrder(bocPayOrderInfo);
    }


    private CodePayFixmedinsApiRespDO queryResult(BocResultDTO bocPayRespDTO) {
        CodePayFixmedinsApiRespDO codePayFixmedinsApiRespDO = new CodePayFixmedinsApiRespDO();
        codePayFixmedinsApiRespDO.setRetCode(RetCodeEmum.RET_CODE_0.getCode());
        if (BocOnePayConst.RESP_SUCCESS_CODE.equals(bocPayRespDTO.getRespCode())) {
            if (BocOnePayConst.RESP_SUCCESS_CODE.equals(bocPayRespDTO.getOldRespCode())) {
                codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_1.getCode());
            } else {
                codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_3.getCode());
            }
            codePayFixmedinsApiRespDO.setBankSerno(bocPayRespDTO.getOrderNo());
            codePayFixmedinsApiRespDO.setRetMsg("查询成功，原交易结果为：" + bocPayRespDTO.getOldRespMsg());
            codePayFixmedinsApiRespDO.setSetlTime(new Date());
        } else if (BocOnePayConst.RESP_UNKNOW_CODE.equals(bocPayRespDTO.getRespCode()) || StringUtils.isBlank(bocPayRespDTO.getRespCode())) {
            codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_3.getCode());
            codePayFixmedinsApiRespDO.setRetMsg(bocPayRespDTO.getRespMsg());
        }else {
            codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_2.getCode());
            codePayFixmedinsApiRespDO.setRetMsg(bocPayRespDTO.getRespMsg());
        }
        return codePayFixmedinsApiRespDO;
    }

    private CodePayFixmedinsApiRespDO payResult(BocResultDTO bocPayRespDTO) {
        CodePayFixmedinsApiRespDO codePayFixmedinsApiRespDO = new CodePayFixmedinsApiRespDO();
        codePayFixmedinsApiRespDO.setRetCode(RetCodeEmum.RET_CODE_0.getCode());
        if (BocOnePayConst.RESP_SUCCESS_CODE.equals(bocPayRespDTO.getRespCode())) {
            codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_1.getCode());
            codePayFixmedinsApiRespDO.setBankSerno(bocPayRespDTO.getOrderNo());
            codePayFixmedinsApiRespDO.setRetMsg(bocPayRespDTO.getRespMsg());
        } else if (BocOnePayConst.RESP_UNKNOW_CODE.equals(bocPayRespDTO.getRespCode()) || StringUtils.isBlank(bocPayRespDTO.getRespCode())) {
            codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_3.getCode());
            codePayFixmedinsApiRespDO.setRetMsg(bocPayRespDTO.getRespMsg());
        }else {
            codePayFixmedinsApiRespDO.setPayFlag(PayFlagEmum.PAY_FLAG_EMUM_2.getCode());
            codePayFixmedinsApiRespDO.setRetMsg(bocPayRespDTO.getRespMsg());
        }
        return codePayFixmedinsApiRespDO;
    }

    private CodePayFixmedinsApiRespDO refundResult(BocResultDTO bocPayRespDTO) {
        CodePayFixmedinsApiRespDO codePayFixmedinsApiRespDO = new CodePayFixmedinsApiRespDO();

        if (BocOnePayConst.RESP_SUCCESS_CODE.equals(bocPayRespDTO.getRespCode())) {
            codePayFixmedinsApiRespDO.setRetCode(RetCodeEmum.RET_CODE_0.getCode());
            codePayFixmedinsApiRespDO.setRetMsg(bocPayRespDTO.getRespMsg());
            codePayFixmedinsApiRespDO.setReturnFlag(PayFlagEmum.PAY_FLAG_EMUM_1.getCode());
            codePayFixmedinsApiRespDO.setBankSerno(bocPayRespDTO.getOrderNo());
        }
        return codePayFixmedinsApiRespDO;
    }


}
